import os, sys

parent_path = os.path.abspath(os.path.join(__file__, *([".."] * 4)))
sys.path.insert(0, parent_path)

import traceback, requests, threading, cv2, io
import ftplib
from queue import Queue
from typing import *
from core.task.modules.processors.base_processor import BaseProcessor
from core.utils.logger import logging


class FTPServer(BaseProcessor):
    """将数据通过http回传到接口
    keys = {
        in:
    }
    """

    def __init__(
        self,
        keys,
        FTPServer_host=None,
        FTPServer_port=None,
        FTPServer_user=None,
        FTPServer_passwd=None,
        FTPServer_save_path=None,
    ) -> None:
        self.status = 0
        self.keys = keys
        self.host = FTPServer_host
        self.user = FTPServer_user
        self.passwd = FTPServer_passwd
        self.port = FTPServer_port
        self.save_path = FTPServer_save_path
        self.buffer_seq = Queue(maxsize=128)

    def _init_check(self):
        assert "in" in self.keys  # 需要上传的图片数据, 应当为一个数组
        assert "out" in self.keys  # 用于保存上传路径结果
        assert (
            "file_names" in self.keys
        )  # 对应图片需要保存的文件名或者是文件路径, 比如图片是由http下载而来, 那这里可以给下载地址
        assert not self.host is None
        assert not self.user is None
        assert not self.passwd is None
        assert not self.port is None
        try:
            ftp: ftplib.FTP = ftplib.FTP()
            ftp.connect(self.host, self.port, timeout=10)
            ftp.login(self.user, self.passwd)
            ftp.close()
        except:
            raise Exception(traceback.format_exc())

    def _set(self, data: Dict):
        if data.get("FTPServer_host", False):
            self.host = data["FTPServer_host"]
        if data.get("FTPServer_port", False):
            self.port = data["FTPServer_port"]
        if data.get("FTPServer_user", False):
            self.user = data["FTPServer_user"]
        if data.get("FTPServer_passwd", False):
            self.passwd = data["FTPServer_passwd"]

    def _mkd(self, ftp, dirname):
        """mkd方法的包装, 从而不需要对文件夹是否已存在进行判断"""
        try:
            ftp.mkd(dirname)
        except Exception as e:
            pass

    def upload(self, fp, file_path):
        """FTP上传文件"""
        try:
            ftp: ftplib.FTP = ftplib.FTP()
            ftp.connect(self.host, self.port)
            ftp.login(self.user, self.passwd)
            dirname = os.path.dirname(file_path)
            dirname_split = dirname.split("/")
            for idx_, dirname_ in enumerate(dirname_split):  # 循环创建路径
                if len(dirname_) > 0:
                    self._mkd(ftp, "/".join(dirname_split[: idx_ + 1]))
            ftp.storbinary(f"STOR {file_path}", fp)  # 传输文件
            ftp.close()
            return True
        except Exception as e:
            logging.error(e)
            return False

    def upload_img(self, imgs, save_paths):
        """以多线程的方式从内存上传图片到FTP服务器"""
        try:
            for img, file_path in zip(imgs, save_paths):
                extension = os.path.splitext(file_path)[-1]
                ret, img_encode = cv2.imencode(ext=extension, img=img)
                self.upload(io.BytesIO(img_encode.tobytes()), file_path)
        except Exception as e:
            logging.error(traceback.format_exc())

    def _call(self, data: Dict) -> Dict:
        upload_data = data[self.keys["in"]]
        file_names = data[self.keys["file_names"]]
        save_paths = [
            self.save_path + "/" + os.path.basename(file_name)
            for file_name in file_names
        ]
        threading.Thread(target=self.upload_img, args=(upload_data, save_paths)).start()
        data[self.keys["out"]] = save_paths
        return data


if __name__ == "__main__":
    print("")
